Skip to content

feat: Add SeedsToTracks to Examples - #5845

Merged
kodiakhq[bot] merged 3 commits into
acts-project:mainfrom
andiwand:seeds-to-tracks
Aug 10, 2026
Merged

feat: Add SeedsToTracks to Examples#5845
kodiakhq[bot] merged 3 commits into
acts-project:mainfrom
andiwand:seeds-to-tracks

Conversation

@andiwand

@andiwand andiwand commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Turns seeds into tracks with one track state per space-point source link, and
stores the seed estimate on the innermost state.

addSeeding built the seed-tracks through SeedsToProtoTracks and
ProtoTracksToTracks so far. A proto track is a flat list of measurement
indices, so that route drops the structure the seed carries and leaves two
things resting on the order in which seedToProtoTrack happens to flatten the
space points: which state is the innermost, and that the estimate of a seed
still lines up with its proto track. TrackParamsEstimationAlgorithm expresses
the estimate on the bottom space point's surface, which a seed names directly.

The estimate is allocated once as predicted and shared as filtered and
smoothed, since it is all that is known at that state.

With a tracking geometry the track states also get their reference surface,
which bound parameters on a state need in order to mean anything.

--- END COMMIT MESSAGE ---

First of four. Review order:

  1. this one, SeedsToTracks
  2. refactor: Rename TrackFitterPerformance to TrackParameterPerformance #5841, the performance writer rename
  3. feat: Add TrackExtrapolationAlgorithm #5842, TrackExtrapolationAlgorithm
  4. feat: Write seed parameter performance from addSeeding #5721, seed parameter performance in addSeeding

1 to 3 are independent of each other, 4 needs all of them. All of them target
main, so the diff of 4 contains 1 to 3 until they merge. #5846 is a small fix
found along the way and is independent of all of these.

SeedsToProtoTracks stays, the proto tracks are still written by
addSeedPerformanceWriters.

Validation

The seed-tracks come out identical to the ProtoTracksToTracks route:
seedToProtoTrack walks seed.spacePoints() and sp.sourceLinks() in the
same nested order, so the states, their order, their source links and
nMeasurements all match. Measured through #5721 on 100 particle-gun events,
the residual and pull histograms of the seed estimate agree to the last digit
between the two routes.

The python test suite gives the same set of failures as main on the same
machine.

Turns seeds into tracks with one track state per space-point source link, and
stores the seed estimate on the innermost state.

`addSeeding` built the `seed-tracks` through `SeedsToProtoTracks` and
`ProtoTracksToTracks` so far. A proto track is a flat list of measurement
indices, so that route loses the structure the seed carries and leaves two
things resting on the order in which `seedToProtoTrack` happens to flatten the
space points: which state is the innermost, and that the estimate of a seed
still lines up with its proto track. `TrackParamsEstimationAlgorithm` expresses
the estimate on the bottom space point's surface, which a seed names directly.

The estimate is allocated once as predicted and shared as filtered and
smoothed, since it is all that is known at that state.

With a tracking geometry the track states also get their reference surface,
which bound parameters on a state need to mean anything.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FxPc2jP43AQuQKz8c4qsaC
@github-actions github-actions Bot added the Component - Examples Affects the Examples module label Aug 7, 2026
@andiwand
andiwand marked this pull request as ready for review August 7, 2026 12:11
@github-actions github-actions Bot added this to the next milestone Aug 7, 2026
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Public API surface diff

No change to the public API surface. ✅

@andiwand andiwand changed the title feat: Add SeedsToTracks feat: Add SeedsToTracks to Examples Aug 7, 2026
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

📊: Physics performance monitoring for a209b67

Full contents

physmon summary

❗️: Downstream build failure

  • eic-shell EICrecon (cc @acts-project/epic-contacts)

@benjaminhuth benjaminhuth left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@paulgessinger paulgessinger modified the milestone: next Aug 10, 2026
@sonarqubecloud

Copy link
Copy Markdown

@kodiakhq
kodiakhq Bot merged commit a1d0e8b into acts-project:main Aug 10, 2026
44 checks passed
@andiwand
andiwand deleted the seeds-to-tracks branch August 11, 2026 05:13
@andiwand andiwand modified the milestones: next, v47.4.0 Aug 15, 2026
andiwand added a commit to andiwand/acts that referenced this pull request Aug 17, 2026
Moves the track parameters of a track container onto a common surface,
typically a perigee.

That is what makes a seed estimate comparable to truth. The estimate
sits on
the bottom space point's sensor, where the truth reference has to be
carried
from the production vertex through the bending in between, so the
comparison
belongs on a perigee.

Only the track-level parameters are moved. The states are shared with
the input
container rather than copied, so they keep the parameters on their own
surfaces
and the output has the same layering a fitter produces, without a second
copy of
the state backend. Tracks whose extrapolation fails are dropped, so any
truth
matching has to run downstream.

`Acts::findTrackStateForExtrapolation` is fixed along with it, for
tracks that
carry parameters on only some of their states - every seed track from
acts-project#5845,
where only the bottom space point holds the estimate. `firstOrLast`
intersects
both ends unconditionally to compare their distances, and the helper
only
asserted that the state it intersects has smoothed or filtered
parameters, so a
release build read an unallocated parameter slot. A state without
parameters now
yields no intersection instead, so such a track extrapolates from the
end that
does carry them rather than being rejected.

Used by acts-project#5721, nothing else in the repository calls it yet.

### Notes

- `Acts::extrapolateTrackToReferenceSurface` is not called; its body is
reproduced in the algorithm instead. The helper takes a single track
proxy and
does both halves through it: it reads the states off that proxy to pick
the
state to start from, and it writes the extrapolated parameters back onto
it in
  place. Here the two cannot be the same proxy.
  - Reading has to happen on the input, which is a read-only
    `ConstTrackContainer` off the whiteboard. `parameters()` and
`setReferenceSurface()` are `requires(!ReadOnly)`, so instantiating the
    helper on an input track does not compile.
- Writing has to happen on the output track, which is mutable but whose
container is paired with an empty `Acts::VectorMultiTrajectory`, because
`Acts::TrackContainer` cannot pair a mutable track backend with a
read-only
state backend. The input state backend is only attached at the very end,
when the const output container is built, so the tip and stem indices
that
`copyFromShallow` carries over do not resolve during the loop. Calling
the
helper on the output track would compile and then walk an empty backend.

  `Acts::findTrackStateForExtrapolation` and the `ForcedSurfaceReached`
propagate call are used directly instead, which is the helper minus the
write-back. An overload that separates the state source from the
parameter
destination, or one that returns the `BoundTrackParameters` rather than
  writing them, would let this call into Core; kept out of this PR.
- On the second commit, which is the Core fix. It was raised in review
on the
first one, where the algorithm instead checked the precondition up front
and
  dropped those tracks.
- The fallback needs no new branching: the `firstOrLast` comparison
already
handles an invalid intersection, which carries an infinite path length
and
so loses to the other end. A seed track therefore extrapolates from its
bottom space point under any strategy, and passing `first` in acts-project#5721 is
an
    optimisation rather than a requirement.
- `CompatibleTrackStateNotFound` is now reported when no end can be
started
from, as opposed to `ReferenceSurfaceUnreachable` when the ends do carry
    parameters but do not reach the surface.
- The parameters come from `Acts::TrackStateProxy::parameters` rather
than a
second smoothed-over-filtered ladder, so the distance is measured on the
same parameters that `createParametersFromState` starts the propagation
from. That also admits a state holding only predicted parameters, which
the
old ladder rejected even though the propagation would have used them.
- Behaviour is unchanged wherever every measurement state carries
parameters,
    which covers both existing `firstOrLast` callers, `KalmanFitter` and
`TrackFindingAlgorithm`. `findTrackStateForExtrapolation` had no unit
test
coverage at all; the new cases in `TrackHelpersTests` need no propagator
and
    fail on the unpatched header.
- `Acts::TrackProxy::copyFrom`, the deep copy, is not an alternative to
sharing
the states: it copies every state with a hardcoded
`TrackStatePropMask::All`,
which throws for a state that holds no parameters at all - every state
of a
seed track except the innermost. Passing `srcTrackState.getMask()` there
would
  fix it, kept out of this PR.
- `Acts::TrackExtrapolationStrategy` gets python bindings here.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
yannikaMatt pushed a commit to yannikaMatt/acts that referenced this pull request Aug 21, 2026
Turns seeds into tracks with one track state per space-point source link, and
stores the seed estimate on the innermost state.

`addSeeding` built the `seed-tracks` through `SeedsToProtoTracks` and
`ProtoTracksToTracks` so far. A proto track is a flat list of measurement
indices, so that route drops the structure the seed carries and leaves two
things resting on the order in which `seedToProtoTrack` happens to flatten the
space points: which state is the innermost, and that the estimate of a seed
still lines up with its proto track. `TrackParamsEstimationAlgorithm` expresses
the estimate on the bottom space point's surface, which a seed names directly.

The estimate is allocated once as predicted and shared as filtered and
smoothed, since it is all that is known at that state.

With a tracking geometry the track states also get their reference surface,
which bound parameters on a state need in order to mean anything.
yannikaMatt pushed a commit to yannikaMatt/acts that referenced this pull request Aug 21, 2026
Moves the track parameters of a track container onto a common surface,
typically a perigee.

That is what makes a seed estimate comparable to truth. The estimate
sits on
the bottom space point's sensor, where the truth reference has to be
carried
from the production vertex through the bending in between, so the
comparison
belongs on a perigee.

Only the track-level parameters are moved. The states are shared with
the input
container rather than copied, so they keep the parameters on their own
surfaces
and the output has the same layering a fitter produces, without a second
copy of
the state backend. Tracks whose extrapolation fails are dropped, so any
truth
matching has to run downstream.

`Acts::findTrackStateForExtrapolation` is fixed along with it, for
tracks that
carry parameters on only some of their states - every seed track from
acts-project#5845,
where only the bottom space point holds the estimate. `firstOrLast`
intersects
both ends unconditionally to compare their distances, and the helper
only
asserted that the state it intersects has smoothed or filtered
parameters, so a
release build read an unallocated parameter slot. A state without
parameters now
yields no intersection instead, so such a track extrapolates from the
end that
does carry them rather than being rejected.

Used by acts-project#5721, nothing else in the repository calls it yet.

### Notes

- `Acts::extrapolateTrackToReferenceSurface` is not called; its body is
reproduced in the algorithm instead. The helper takes a single track
proxy and
does both halves through it: it reads the states off that proxy to pick
the
state to start from, and it writes the extrapolated parameters back onto
it in
  place. Here the two cannot be the same proxy.
  - Reading has to happen on the input, which is a read-only
    `ConstTrackContainer` off the whiteboard. `parameters()` and
`setReferenceSurface()` are `requires(!ReadOnly)`, so instantiating the
    helper on an input track does not compile.
- Writing has to happen on the output track, which is mutable but whose
container is paired with an empty `Acts::VectorMultiTrajectory`, because
`Acts::TrackContainer` cannot pair a mutable track backend with a
read-only
state backend. The input state backend is only attached at the very end,
when the const output container is built, so the tip and stem indices
that
`copyFromShallow` carries over do not resolve during the loop. Calling
the
helper on the output track would compile and then walk an empty backend.

  `Acts::findTrackStateForExtrapolation` and the `ForcedSurfaceReached`
propagate call are used directly instead, which is the helper minus the
write-back. An overload that separates the state source from the
parameter
destination, or one that returns the `BoundTrackParameters` rather than
  writing them, would let this call into Core; kept out of this PR.
- On the second commit, which is the Core fix. It was raised in review
on the
first one, where the algorithm instead checked the precondition up front
and
  dropped those tracks.
- The fallback needs no new branching: the `firstOrLast` comparison
already
handles an invalid intersection, which carries an infinite path length
and
so loses to the other end. A seed track therefore extrapolates from its
bottom space point under any strategy, and passing `first` in acts-project#5721 is
an
    optimisation rather than a requirement.
- `CompatibleTrackStateNotFound` is now reported when no end can be
started
from, as opposed to `ReferenceSurfaceUnreachable` when the ends do carry
    parameters but do not reach the surface.
- The parameters come from `Acts::TrackStateProxy::parameters` rather
than a
second smoothed-over-filtered ladder, so the distance is measured on the
same parameters that `createParametersFromState` starts the propagation
from. That also admits a state holding only predicted parameters, which
the
old ladder rejected even though the propagation would have used them.
- Behaviour is unchanged wherever every measurement state carries
parameters,
    which covers both existing `firstOrLast` callers, `KalmanFitter` and
`TrackFindingAlgorithm`. `findTrackStateForExtrapolation` had no unit
test
coverage at all; the new cases in `TrackHelpersTests` need no propagator
and
    fail on the unpatched header.
- `Acts::TrackProxy::copyFrom`, the deep copy, is not an alternative to
sharing
the states: it copies every state with a hardcoded
`TrackStatePropMask::All`,
which throws for a state that holds no parameters at all - every state
of a
seed track except the innermost. Passing `srcTrackState.getMask()` there
would
  fix it, kept out of this PR.
- `Acts::TrackExtrapolationStrategy` gets python bindings here.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
yannikaMatt pushed a commit to yannikaMatt/acts that referenced this pull request Aug 21, 2026
Turns seeds into tracks with one track state per space-point source link, and
stores the seed estimate on the innermost state.

`addSeeding` built the `seed-tracks` through `SeedsToProtoTracks` and
`ProtoTracksToTracks` so far. A proto track is a flat list of measurement
indices, so that route drops the structure the seed carries and leaves two
things resting on the order in which `seedToProtoTrack` happens to flatten the
space points: which state is the innermost, and that the estimate of a seed
still lines up with its proto track. `TrackParamsEstimationAlgorithm` expresses
the estimate on the bottom space point's surface, which a seed names directly.

The estimate is allocated once as predicted and shared as filtered and
smoothed, since it is all that is known at that state.

With a tracking geometry the track states also get their reference surface,
which bound parameters on a state need in order to mean anything.
yannikaMatt pushed a commit to yannikaMatt/acts that referenced this pull request Aug 21, 2026
Moves the track parameters of a track container onto a common surface,
typically a perigee.

That is what makes a seed estimate comparable to truth. The estimate
sits on
the bottom space point's sensor, where the truth reference has to be
carried
from the production vertex through the bending in between, so the
comparison
belongs on a perigee.

Only the track-level parameters are moved. The states are shared with
the input
container rather than copied, so they keep the parameters on their own
surfaces
and the output has the same layering a fitter produces, without a second
copy of
the state backend. Tracks whose extrapolation fails are dropped, so any
truth
matching has to run downstream.

`Acts::findTrackStateForExtrapolation` is fixed along with it, for
tracks that
carry parameters on only some of their states - every seed track from
acts-project#5845,
where only the bottom space point holds the estimate. `firstOrLast`
intersects
both ends unconditionally to compare their distances, and the helper
only
asserted that the state it intersects has smoothed or filtered
parameters, so a
release build read an unallocated parameter slot. A state without
parameters now
yields no intersection instead, so such a track extrapolates from the
end that
does carry them rather than being rejected.

Used by acts-project#5721, nothing else in the repository calls it yet.

### Notes

- `Acts::extrapolateTrackToReferenceSurface` is not called; its body is
reproduced in the algorithm instead. The helper takes a single track
proxy and
does both halves through it: it reads the states off that proxy to pick
the
state to start from, and it writes the extrapolated parameters back onto
it in
  place. Here the two cannot be the same proxy.
  - Reading has to happen on the input, which is a read-only
    `ConstTrackContainer` off the whiteboard. `parameters()` and
`setReferenceSurface()` are `requires(!ReadOnly)`, so instantiating the
    helper on an input track does not compile.
- Writing has to happen on the output track, which is mutable but whose
container is paired with an empty `Acts::VectorMultiTrajectory`, because
`Acts::TrackContainer` cannot pair a mutable track backend with a
read-only
state backend. The input state backend is only attached at the very end,
when the const output container is built, so the tip and stem indices
that
`copyFromShallow` carries over do not resolve during the loop. Calling
the
helper on the output track would compile and then walk an empty backend.

  `Acts::findTrackStateForExtrapolation` and the `ForcedSurfaceReached`
propagate call are used directly instead, which is the helper minus the
write-back. An overload that separates the state source from the
parameter
destination, or one that returns the `BoundTrackParameters` rather than
  writing them, would let this call into Core; kept out of this PR.
- On the second commit, which is the Core fix. It was raised in review
on the
first one, where the algorithm instead checked the precondition up front
and
  dropped those tracks.
- The fallback needs no new branching: the `firstOrLast` comparison
already
handles an invalid intersection, which carries an infinite path length
and
so loses to the other end. A seed track therefore extrapolates from its
bottom space point under any strategy, and passing `first` in acts-project#5721 is
an
    optimisation rather than a requirement.
- `CompatibleTrackStateNotFound` is now reported when no end can be
started
from, as opposed to `ReferenceSurfaceUnreachable` when the ends do carry
    parameters but do not reach the surface.
- The parameters come from `Acts::TrackStateProxy::parameters` rather
than a
second smoothed-over-filtered ladder, so the distance is measured on the
same parameters that `createParametersFromState` starts the propagation
from. That also admits a state holding only predicted parameters, which
the
old ladder rejected even though the propagation would have used them.
- Behaviour is unchanged wherever every measurement state carries
parameters,
    which covers both existing `firstOrLast` callers, `KalmanFitter` and
`TrackFindingAlgorithm`. `findTrackStateForExtrapolation` had no unit
test
coverage at all; the new cases in `TrackHelpersTests` need no propagator
and
    fail on the unpatched header.
- `Acts::TrackProxy::copyFrom`, the deep copy, is not an alternative to
sharing
the states: it copies every state with a hardcoded
`TrackStatePropMask::All`,
which throws for a state that holds no parameters at all - every state
of a
seed track except the innermost. Passing `srcTrackState.getMask()` there
would
  fix it, kept out of this PR.
- `Acts::TrackExtrapolationStrategy` gets python bindings here.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Component - Examples Affects the Examples module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants